#include "Threading.hpp"

#include <iomanip>

 void Threading::dumpThreadInfo(std::ostream & os, std::string const &s) {
#ifdef DEBUG_NUMA
  std::stringstream ss;
  uint cpu, node = 0;
  // sys_getcpu(&cpu, &node);
  cpu = sched_getcpu();
  node = numa_node_of_cpu(cpu);
  ss << "I am " << std::this_thread::get_id() << " processing " << s << 
    " and running on cpu=" << cpu << " node=" << node << "\n";
  Threading::dump(os, ss.str());
#endif // DEBUG_NUMA
}

 void Threading::dumpMemInfo(std::ostream & os, void *addr) {
#ifdef DEBUG_NUMA_MEM

#define OSTREAM_GRANULARITY 1000
#define NB_CPUS 32
#define CACHE_LINE_SIZE 64
   static uint64_t count[NB_CPUS][CACHE_LINE_SIZE/(sizeof(uint64_t))] = // CPUx8
     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x1
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x8
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  // 16x16
     };
  static double same = 0.0, different = 0.0;
  uint cpu = 0, node = 0;
  // sys_getcpu(&cpu, &node);
  cpu = sched_getcpu();
  node = numa_node_of_cpu(cpu);

  count[cpu][0]++;

  int status;
  move_pages(0 /*self memory */, 1, &addr, NULL, &status, 0);    
  double inc = ((status == node) ? 1.0 : 0.0);

  count_mutex().lock();
  same += inc;
  different += (1-inc);
  count_mutex().unlock();

  if (count[cpu][0] % OSTREAM_GRANULARITY == 0) {
    std::stringstream ss;
    ss << "I am thread  0x" << std::hex << std::this_thread::get_id()
       << " currently running on cpu:" << std::dec << cpu << " on node:" 
       << node << std::hex;
    ss << "\t Page @0x" << ((int64_t)addr & 0xfffffffffffff700)
       << std::dec << "  on node: " << status;
    ss << " same node access % " << (100.0*same/(same+different)) 
       << " (count: " << count[cpu][0] << ")""\n";
    Threading::dump(os, ss.str());
  }
#endif // DEBUG_NUMA_MEM
}
